#include "stdafx.h"
#include "cppflibinc.h"
#include "TestMiscFilePath.h"

using namespace cppflib;
using namespace cppflib::io;
using namespace cppflib::os;
using namespace cppflib::util;
using namespace cppflib::util::zip;
using namespace cppflib::collections;
using namespace cppflib::exceptions;

static void TestTimeDuration()
{
   cppmempool::MemPoolWrap memPool;

   TimeDuration *td = new TimeDuration(1, -1, 1, -1, 1);
   assert(td->Days() == 0);
   assert(td->Hours() == 23);
   assert(td->Mins() == 0);
   assert(td->Seconds() == 59);
   assert(td->MilliSeconds() == 1);
   assert(td->TotalTicks() == I64N(828590010000));
   assert(td->MakeAbsolute().TotalTicks() == I64N(828590010000));
 
   td = new TimeDuration(1, -1, 1);
   assert(td->Days() == 0);
   assert(td->Hours() == 0);
   assert(td->Mins() == 59);
   assert(td->Seconds() == 1);
   assert(td->MilliSeconds() == 0);
   assert(!td->IsNeg());

   td = new TimeDuration(2, -5, -14, -9, 666);
   assert(td->Days() == 1);
   assert(td->Hours() == 18);
   assert(td->Mins() == 45);
   assert(td->Seconds() == 51);
   assert(td->MilliSeconds() == 666);
 
   TimeDuration *td2 = new TimeDuration(-7, 22, 14, -29, 77);
   assert(td2->Days() == -6);
   assert(td2->Hours() == -1);
   assert(td2->Mins() == -46);
   assert(td2->Seconds() == -28);
   assert(td2->MilliSeconds() == -923);
   assert(td2->IsNeg());
   assert(td2->TotalTicks() == I64N(-5247889230000));
   assert(td2->TotalAbsoluteTicks() == I64N(5247889230000));

   TimeDuration *td3 = new TimeDuration(-6, -1, -46, -28, -923);

   assert(*td2 == *td3);
   td3->Add(*td);
   assert(*td2 < *td3);
   td2->MakeAbsolute();
   assert(*td2 > *td3);


   try {
      td = new TimeDuration(99999999, 999999, 99999, 9999, 0);
      assert(false);
   }
   catch (exceptions::OverflowException &exp) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), exp.GetMsg());
   }

   try {
      td = new TimeDuration(I64N(0x8000000000000000));
      td->Negate();
      assert(false);
   }
   catch (exceptions::OverflowException &exp) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), exp.GetMsg());
   }
   
}

static void TestDateTime()
{
   cppmempool::MemPoolWrap memPool;

   DateTime *pNow = DateTime::Now();
   CFString timeStr(pNow->ToString());
   debug::Print(debug::DL_DEBUG, _S("local now = %s\n"), static_cast<pcwstr_t>(timeStr));

   DateTime *pUtcNow = DateTime::UtcNow();
   timeStr = pUtcNow->ToString();
   debug::Print(debug::DL_DEBUG, _S("UTC now = %s\n"), static_cast<pcwstr_t>(timeStr));

   dayofweek_t dw = pNow->DayOfWeek();
   timeStr = lang::Enum::GetString<dayofweek_t>(dw);
   debug::Print(debug::DL_DEBUG, _S("day of week = %s\n"), static_cast<pcwstr_t>(timeStr));


   DateTime *pTime1 = new DateTime(2009, 1, 1);
   assert(pTime1->Year() == 2009);
   assert(pTime1->Month() == 1);
   assert(pTime1->Day() == 1);
   assert(pTime1->Ticks() == I64N(633663648000000000));

   pTime1 = new DateTime(2009, 12, 31);
   assert(pTime1->Year() == 2009);
   assert(pTime1->Month() == 12);
   assert(pTime1->Day() == 31);
   assert(pTime1->Ticks() == I64N(633978144000000000));

   pTime1 = new DateTime(2010, 1, 1);
   assert(pTime1->Year() == 2010);
   assert(pTime1->Month() == 1);
   assert(pTime1->Day() == 1);
   assert(pTime1->Ticks() == I64N(633979008000000000));

   pTime1 = new DateTime(2008, 1, 1);
   assert(pTime1->Year() == 2008);
   assert(pTime1->Month() == 1);
   assert(pTime1->Day() == 1);
   assert(pTime1->Ticks() == I64N(633347424000000000));

   pTime1 = new DateTime(2008, 1, 1, 3, 0, 0);
   assert(pTime1->Year() == 2008);
   assert(pTime1->Month() == 1);
   assert(pTime1->Day() == 1);
   assert(pTime1->Hour() == 3);
   assert(pTime1->Min() == 0);
   assert(pTime1->Sec() == 0);
   assert(pTime1->Ticks() == I64N(633347532000000000));
   
   pTime1 = new DateTime(2008, 12, 31);
   assert(pTime1->Year() == 2008);
   assert(pTime1->Month() == 12);
   assert(pTime1->Day() == 31);
   assert(pTime1->Ticks() == I64N(633662784000000000));

   pTime1 = new DateTime(2008, 12, 31, 7, 0, 0);
   assert(pTime1->Year() == 2008);
   assert(pTime1->Month() == 12);
   assert(pTime1->Day() == 31);
   assert(pTime1->Hour() == 7);
   assert(pTime1->Min() == 0);
   assert(pTime1->Sec() == 0);
   assert(pTime1->Ticks() == I64N(633663036000000000));

   DateTime *pTime2 = new DateTime(2010, 1, 30, 18, 48, 12);
   assert(pTime2->Year() == 2010);
   assert(pTime2->Month() == 1);
   assert(pTime2->Day() == 30);
   assert(pTime2->Hour() == 18);
   assert(pTime2->Min() == 48);
   assert(pTime2->Sec() == 12);
   assert(pTime2->Ticks() == I64N(634004740920000000));

   DateTime *pTime3 = new DateTime(2010, 12, 31, 23, 59, 59, 991);
   assert(pTime3->Year() == 2010);
   assert(pTime3->Month() == 12);
   assert(pTime3->Day() == 31);
   assert(pTime3->Hour() == 23);
   assert(pTime3->Min() == 59);
   assert(pTime3->Sec() == 59);
   assert(pTime3->MilliSec() == 991);
   assert(pTime3->Ticks() == I64N(634294367999910000));

   DateTime *pTime4 = new DateTime(2000, 2, 29, 1, 1, 1, 2);
   assert(pTime4->Year() == 2000);
   assert(pTime4->Month() == 2);
   assert(pTime4->Day() == 29);
   assert(pTime4->Hour() == 1);
   assert(pTime4->Min() == 1);
   assert(pTime4->Sec() == 1);
   assert(pTime4->MilliSec() == 2);
   assert(pTime4->Ticks() == I64N(630873828610020000));

   DateTime *pTime5 = new DateTime(1997, 7, 1, 3, 9, 2, 2);
   assert(pTime5->Year() == 1997);
   assert(pTime5->Month() == 7);
   assert(pTime5->Day() == 1);
   assert(pTime5->Hour() == 3);
   assert(pTime5->Min() == 9);
   assert(pTime5->Sec() == 2);
   assert(pTime5->MilliSec() == 2);
   assert(pTime5->Ticks() == I64N(630033233420020000));

   DateTime *pTime6 = new DateTime(1573, 8, 1, 12, 19, 42, 888);
   assert(pTime6->Year() == 1573);
   assert(pTime6->Month() == 8);
   assert(pTime6->Day() == 1);
   assert(pTime6->Hour() == 12);
   assert(pTime6->Min() == 19);
   assert(pTime6->Sec() == 42);
   assert(pTime6->MilliSec() == 888);
   assert(pTime6->Ticks() == I64N(496258715828880000));


   DateTime *pTime7 = new DateTime(2003, 5, 1, 12, 19, 42, 888);
   assert(pTime7->Year() == 2003);
   assert(pTime7->Month() == 5);
   assert(pTime7->Day() == 1);
   assert(pTime7->Hour() == 12);
   assert(pTime7->Min() == 19);
   assert(pTime7->Sec() == 42);
   assert(pTime7->MilliSec() == 888);
   assert(pTime7->Ticks() == I64N(631873883828880000));

   pTime7 = new DateTime(1992, 10, 31, 12, 19, 42, 888);
   assert(pTime7->Year() == 1992);
   assert(pTime7->Month() == 10);
   assert(pTime7->Day() == 31);
   assert(pTime7->Hour() == 12);
   assert(pTime7->Min() == 19);
   assert(pTime7->Sec() == 42);
   assert(pTime7->MilliSec() == 888);
   assert(pTime7->Ticks() == I64N(628561307828880000));

   pTime7 = new DateTime(1951, 11, 22, 12, 19, 42, 888);
   assert(pTime7->Year() == 1951);
   assert(pTime7->Month() == 11);
   assert(pTime7->Day() == 22);
   assert(pTime7->Hour() == 12);
   assert(pTime7->Min() == 19);
   assert(pTime7->Sec() == 42);
   assert(pTime7->MilliSec() == 888);
   assert(pTime7->Ticks() == I64N(615641051828880000));

   pTime7 = new DateTime(1877, 6, 30, 12, 19, 42, 888);
   assert(pTime7->Year() == 1877);
   assert(pTime7->Month() == 6);
   assert(pTime7->Day() == 30);
   assert(pTime7->Hour() == 12);
   assert(pTime7->Min() == 19);
   assert(pTime7->Sec() == 42);
   assert(pTime7->MilliSec() == 888);
   assert(pTime7->Ticks() == I64N(592164443828880000));

   pTime7 = new DateTime(1, 1, 1, 0, 0, 0, 1);
   assert(pTime7->Year() == 1);
   assert(pTime7->Month() == 1);
   assert(pTime7->Day() == 1);
   assert(pTime7->Hour() == 0);
   assert(pTime7->Min() == 0);
   assert(pTime7->Sec() == 0);
   assert(pTime7->MilliSec() == 1);
   assert(pTime7->Ticks() == I64N(10000));

   pTime7 = new DateTime(99, 12, 31, 0, 0, 0, 0);
   assert(pTime7->Year() == 99);
   assert(pTime7->Month() == 12);
   assert(pTime7->Day() == 31);
   assert(pTime7->Hour() == 0);
   assert(pTime7->Min() == 0);
   assert(pTime7->Sec() == 0);
   assert(pTime7->MilliSec() == 0);
   assert(pTime7->Ticks() == I64N(31240512000000000));

   pTime7 = new DateTime(100, 1, 1, 0, 0, 0, 0);
   assert(pTime7->Year() == 100);
   assert(pTime7->Month() == 1);
   assert(pTime7->Day() == 1);
   assert(pTime7->Hour() == 0);
   assert(pTime7->Min() == 0);
   assert(pTime7->Sec() == 0);
   assert(pTime7->MilliSec() == 0);
   assert(pTime7->Ticks() == I64N(31241376000000000));

   pTime7 = new DateTime(101, 1, 1, 0, 0, 0, 0);
   assert(pTime7->Year() == 101);
   assert(pTime7->Month() == 1);
   assert(pTime7->Day() == 1);
   assert(pTime7->Hour() == 0);
   assert(pTime7->Min() == 0);
   assert(pTime7->Sec() == 0);
   assert(pTime7->MilliSec() == 0);
   assert(pTime7->Ticks() == I64N(31556736000000000));

   pTime7 = new DateTime(399, 12, 31, 0, 0, 0, 0);
   assert(pTime7->Year() == 399);
   assert(pTime7->Month() == 12);
   assert(pTime7->Day() == 31);
   assert(pTime7->Hour() == 0);
   assert(pTime7->Min() == 0);
   assert(pTime7->Sec() == 0);
   assert(pTime7->MilliSec() == 0);
   assert(pTime7->Ticks() == I64N(125910720000000000));

   pTime7 = new DateTime(400, 1, 1, 0, 0, 0, 0);
   assert(pTime7->Year() == 400);
   assert(pTime7->Month() == 1);
   assert(pTime7->Day() == 1);
   assert(pTime7->Hour() == 0);
   assert(pTime7->Min() == 0);
   assert(pTime7->Sec() == 0);
   assert(pTime7->MilliSec() == 0);
   assert(pTime7->Ticks() == I64N(125911584000000000));

   pTime7 = new DateTime(401, 1, 1, 0, 0, 0, 0);
   assert(pTime7->Year() == 401);
   assert(pTime7->Month() == 1);
   assert(pTime7->Day() == 1);
   assert(pTime7->Hour() == 0);
   assert(pTime7->Min() == 0);
   assert(pTime7->Sec() == 0);
   assert(pTime7->MilliSec() == 0);
   assert(pTime7->Ticks() == I64N(126227808000000000));

   pTime7 = new DateTime(2, 1, 1, 0, 0, 0, 0);
   assert(pTime7->Year() == 2);
   assert(pTime7->Month() == 1);
   assert(pTime7->Day() == 1);
   assert(pTime7->Hour() == 0);
   assert(pTime7->Min() == 0);
   assert(pTime7->Sec() == 0);
   assert(pTime7->MilliSec() == 0);
   assert(pTime7->Ticks() == I64N(315360000000000));

   pTime7 = new DateTime(9999, 12, 31, 23, 59, 59, 999);
   assert(pTime7->Year() == 9999);
   assert(pTime7->Month() == 12);
   assert(pTime7->Day() == 31);
   assert(pTime7->Hour() == 23);
   assert(pTime7->Min() == 59);
   assert(pTime7->Sec() == 59);
   assert(pTime7->MilliSec() == 999);
   assert(pTime7->Ticks() == I64N(3155378975999990000));

   pTime7 = new DateTime(2000, 1, 1, 11, 34, 23);
   assert(pTime7->Year() == 2000);
   assert(pTime7->Month() == 1);
   assert(pTime7->Day() == 1);
   assert(pTime7->Hour() == 11);
   assert(pTime7->Min() == 34);
   assert(pTime7->Sec() == 23);
   assert(pTime7->MilliSec() == 0);
   assert(pTime7->Ticks() == I64N(630823232630000000));
   
}

static void TestDateTime2()
{
   cppmempool::MemPoolWrap memPool;

   try {
      DateTime t(0, 1, 1);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(10000, 1, 1);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 0, 1);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 13, 1);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 0);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 32);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 1, -1, 0, 0);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 1, 24, 0, 0);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 1, 0, -1, 0);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 1, 0, 60, 0);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 1, 0, 0, -1);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 1, 0, 0, 60);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 1, 0, 0, 0, -1);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

   try {
      DateTime t(1, 1, 1, 0, 0, 0, 1000);
      assert(false);
   }
   catch (exceptions::ArgumentException &e) {
      debug::Print(debug::DL_DEBUG, _S("%s\n"), e.GetMsg());
   }

}

static void TestDateTime3()
{
   cppmempool::MemPoolWrap memPool;

   //////////////////// from past to future ///////////////////////////

   // org non-leap, target non-leap
   DateTime *t = new DateTime(2001, 2, 22, 12, 34, 23);
   t->AddYears(4);
   assert(t->Year() == 2005);
   assert(t->Month() == 2);
   assert(t->Day() == 22);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target leap (before Feb 29)
   t = new DateTime(2000, 2, 22, 12, 34, 23);
   t->AddYears(4);
   assert(t->Year() == 2004);
   assert(t->Month() == 2);
   assert(t->Day() == 22);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);
  
   // org leap, target leap (on Feb 29)
   t = new DateTime(2000, 2, 29, 12, 34, 23);
   t->AddYears(4);
   assert(t->Year() == 2004);
   assert(t->Month() == 2);
   assert(t->Day() == 29);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target leap (after Feb 29)
   t = new DateTime(2000, 3, 1, 12, 34, 23);
   t->AddYears(4);
   assert(t->Year() == 2004);
   assert(t->Month() == 3);
   assert(t->Day() == 1);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target non-leap (before Feb 29)
   t = new DateTime(2000, 2, 22, 12, 34, 23);
   t->AddYears(5);
   assert(t->Year() == 2005);
   assert(t->Month() == 2);
   assert(t->Day() == 22);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target non-leap (on Feb 29)
   t = new DateTime(2000, 2, 29, 12, 34, 23);
   t->AddYears(5);
   assert(t->Year() == 2005);
   assert(t->Month() == 2);
   assert(t->Day() == 28);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target non-leap (after Feb 29)
   t = new DateTime(2000, 3, 2, 12, 34, 23);
   t->AddYears(5);
   assert(t->Year() == 2005);
   assert(t->Month() == 3);
   assert(t->Day() == 2);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org non-leap, target leap (before Feb 29)
   t = new DateTime(2001, 2, 22, 12, 34, 23);
   t->AddYears(3);
   assert(t->Year() == 2004);
   assert(t->Month() == 2);
   assert(t->Day() == 22);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org non-leap, target leap (after Feb 29)
   t = new DateTime(2001, 3, 1, 12, 34, 23);
   t->AddYears(3);
   assert(t->Year() == 2004);
   assert(t->Month() == 3);
   assert(t->Day() == 1);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   //////////////////// from future to past ///////////////////////////

   // org non-leap, target non-leap
   t = new DateTime(2001, 2, 22, 12, 34, 23);
   t->AddYears(-4);
   assert(t->Year() == 1997);
   assert(t->Month() == 2);
   assert(t->Day() == 22);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target leap (before Feb 29)
   t = new DateTime(2000, 2, 22, 12, 34, 23);
   t->AddYears(-4);
   assert(t->Year() == 1996);
   assert(t->Month() == 2);
   assert(t->Day() == 22);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);
  
   // org leap, target leap (on Feb 29)
   t = new DateTime(2000, 2, 29, 12, 34, 23);
   t->AddYears(-4);
   assert(t->Year() == 1996);
   assert(t->Month() == 2);
   assert(t->Day() == 29);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target leap (after Feb 29)
   t = new DateTime(2000, 3, 1, 12, 34, 23);
   t->AddYears(-4);
   assert(t->Year() == 1996);
   assert(t->Month() == 3);
   assert(t->Day() == 1);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target non-leap (before Feb 29)
   t = new DateTime(2000, 2, 22, 12, 34, 23);
   t->AddYears(-5);
   assert(t->Year() == 1995);
   assert(t->Month() == 2);
   assert(t->Day() == 22);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target non-leap (on Feb 29)
   t = new DateTime(2000, 2, 29, 12, 34, 23);
   t->AddYears(-5);
   assert(t->Year() == 1995);
   assert(t->Month() == 2);
   assert(t->Day() == 28);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org leap, target non-leap (after Feb 29)
   t = new DateTime(2000, 3, 2, 12, 34, 23);
   t->AddYears(-5);
   assert(t->Year() == 1995);
   assert(t->Month() == 3);
   assert(t->Day() == 2);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org non-leap, target leap (before Feb 29)
   t = new DateTime(2001, 2, 22, 12, 34, 23);
   t->AddYears(-5);
   assert(t->Year() == 1996);
   assert(t->Month() == 2);
   assert(t->Day() == 22);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // org non-leap, target leap (after Feb 29)
   t = new DateTime(2001, 3, 1, 12, 34, 23);
   t->AddYears(-5);
   assert(t->Year() == 1996);
   assert(t->Month() == 3);
   assert(t->Day() == 1);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // add 0 years
   t = new DateTime(2001, 3, 1, 12, 34, 23);
   t->AddYears(0);
   assert(t->Year() == 2001);
   assert(t->Month() == 3);
   assert(t->Day() == 1);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

}

static void TestDateTime4()
{
   cppmempool::MemPoolWrap memPool;

   // add month forward

   DateTime *t = new DateTime(2001, 3, 31, 12, 34, 23);
   t->AddMonths(4);
   assert(t->Year() == 2001);
   assert(t->Month() == 7);
   assert(t->Day() == 31);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 1, 31, 12, 34, 23);
   t->AddMonths(1);
   assert(t->Year() == 2000);
   assert(t->Month() == 2);
   assert(t->Day() == 29);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 2, 29, 12, 34, 23);
   t->AddMonths(3);
   assert(t->Year() == 2000);
   assert(t->Month() == 5);
   assert(t->Day() == 29);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 1, 11, 12, 34, 23);
   t->AddMonths(25);
   assert(t->Year() == 2002);
   assert(t->Month() == 2);
   assert(t->Day() == 11);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // move month backward
   t = new DateTime(2000, 10, 31, 12, 34, 23);
   t->AddMonths(-9);
   assert(t->Year() == 2000);
   assert(t->Month() == 1);
   assert(t->Day() == 31);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 1, 11, 12, 34, 23);
   t->AddMonths(-5);
   assert(t->Year() == 1999);
   assert(t->Month() == 8);
   assert(t->Day() == 11);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 4, 30, 12, 34, 23);
   t->AddMonths(-2);
   assert(t->Year() == 2000);
   assert(t->Month() == 2);
   assert(t->Day() == 29);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 2, 29, 12, 34, 23);
   t->AddMonths(-2);
   assert(t->Year() == 1999);
   assert(t->Month() == 12);
   assert(t->Day() == 29);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 3, 13, 12, 34, 23);
   t->AddMonths(-24);
   assert(t->Year() == 1998);
   assert(t->Month() == 3);
   assert(t->Day() == 13);
   assert(t->Hour() == 12);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   // add hours, mins, secs, millisecs
   t = new DateTime(2000, 12, 31, 12, 34, 23);
   t->AddHours(12);
   assert(t->Year() == 2001);
   assert(t->Month() == 1);
   assert(t->Day() == 1);
   assert(t->Hour() == 0);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 1, 1, 11, 34, 23);
   t->AddHours(-12);
   assert(t->Year() == 1999);
   assert(t->Month() == 12);
   assert(t->Day() == 31);
   assert(t->Hour() == 23);
   assert(t->Min() == 34);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 1, 1, 11, 34, 23);
   t->AddMinutes(12);
   assert(t->Year() == 2000);
   assert(t->Month() == 1);
   assert(t->Day() == 1);
   assert(t->Hour() == 11);
   assert(t->Min() == 46);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 1, 1, 11, 34, 23);
   t->AddMinutes(-12);
   assert(t->Year() == 2000);
   assert(t->Month() == 1);
   assert(t->Day() == 1);
   assert(t->Hour() == 11);
   assert(t->Min() == 22);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 1, 1, 11, 34, 23);
   t->AddSeconds(60);
   assert(t->Year() == 2000);
   assert(t->Month() == 1);
   assert(t->Day() == 1);
   assert(t->Hour() == 11);
   assert(t->Min() == 35);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 1, 1, 11, 34, 23);
   t->AddSeconds(-60);
   assert(t->Year() == 2000);
   assert(t->Month() == 1);
   assert(t->Day() == 1);
   assert(t->Hour() == 11);
   assert(t->Min() == 33);
   assert(t->Sec() == 23);

   t = new DateTime(2000, 1, 1, 11, 34, 23);
   t->AddMilliSeconds(3000);
   assert(t->Year() == 2000);
   assert(t->Month() == 1);
   assert(t->Day() == 1);
   assert(t->Hour() == 11);
   assert(t->Min() == 34);
   assert(t->Sec() == 26);

   t = new DateTime(2000, 1, 1, 11, 34, 23);
   t->AddMilliSeconds(-4000);
   assert(t->Year() == 2000);
   assert(t->Month() == 1);
   assert(t->Day() == 1);
   assert(t->Hour() == 11);
   assert(t->Min() == 34);
   assert(t->Sec() == 19);

   t = new DateTime(2012, 12, 29, 16, 34, 23);
   t->AddDays(2).AddHours(3).AddMinutes(10);
//   assert(t->DayOfYear() == 366);
   assert(t->Year() == 2012);
   assert(t->Month() == 12);
   assert(t->Day() == 31);
   assert(t->Hour() == 19);
   assert(t->Min() == 44);
   assert(t->Sec() == 23);

   // convert local time / utc time
   DateTime *utcNow = DateTime::UtcNow();
   DateTime *localNow = DateTime::Now();
   DateTime convertLocalNow = utcNow->ToLocalTime();
   assert(localNow->Year() == convertLocalNow.Year());
   assert(localNow->Month() == convertLocalNow.Month());
   assert(localNow->Day() == convertLocalNow.Day());
   assert(localNow->Hour() == convertLocalNow.Hour());
   assert(localNow->Min() == convertLocalNow.Min());
   assert(localNow->Sec() == convertLocalNow.Sec());
   assert(localNow->MilliSec() == convertLocalNow.MilliSec());

   utcNow = DateTime::UtcNow();
   localNow = DateTime::Now();
   DateTime convertUtcNow = localNow->ToUtcTime();
   assert(utcNow->Year() == convertUtcNow.Year());
   assert(utcNow->Month() == convertUtcNow.Month());
   assert(utcNow->Day() == convertUtcNow.Day());
   assert(utcNow->Hour() == convertUtcNow.Hour());
   assert(utcNow->Min() == convertUtcNow.Min());
   assert(utcNow->Sec() == convertUtcNow.Sec());
   assert(utcNow->MilliSec() == convertUtcNow.MilliSec());
}

static void TestDateTime5()
{
   cppmempool::MemPoolWrap memPool;

   // compare
   DateTime *utcNow = DateTime::UtcNow();
   DateTime *localNow = DateTime::Now();
   assert(*utcNow == *localNow);

   DateTime t(1992, 3, 18);
   assert(*utcNow != t);
   assert(*utcNow > t);
   assert(*utcNow >= t);
   assert(*utcNow >= *localNow);
   assert(t < *utcNow);
   assert(t <= *utcNow);
   assert(*localNow <= *utcNow);
   assert(!localNow->Equals(*utcNow));
   assert(localNow->Equals(utcNow->ToLocalTime()));
   assert(localNow->GetHash() != utcNow->GetHash());
   DateTime utcTime(localNow->Ticks(), DateTime::DTK_UTC);
   assert(localNow->GetHash() != utcTime.GetHash());
   DateTime localTime2(*localNow);
   assert(localNow->GetHash() == localTime2.GetHash());

   // misc
   DateTime t2(1999, 5, 11, 9, 12, 34, DateTime::DTK_LOCAL);
   DateTime datePart = t2.Date();
   assert(datePart.Year() == 1999);
   assert(datePart.Month() == 5);
   assert(datePart.Day() == 11);
   assert(datePart.Hour() == 0);
   assert(datePart.Min() == 0);
   assert(datePart.Sec() == 0);
   assert(datePart.MilliSec() == 0);

   TimeDuration td = t2.TimeOfDay();
   assert(td.Hours() == 9);   
   assert(td.Mins() == 12);
   assert(td.Seconds() == 34);

   assert(t2.DayOfYear() == 31 + 28 + 31 + 30 + 11);

   DateTime * today = DateTime::Today();
   assert(today->Year() == localNow->Year());
   assert(today->Month() == localNow->Month());
   assert(today->Day() == localNow->Day());
   assert(today->Hour() == 0);
   assert(today->Min() == 0);
   assert(today->Sec() == 0);
   assert(today->MilliSec() == 0);
   assert(today->Kind() == DateTime::DTK_LOCAL);
   
   DateTime maxValue = DateTime::MaxDateTime();
   assert(maxValue.Year() == 9999);
   assert(maxValue.Month() == 12);
   assert(maxValue.Day() == 31);

   DateTime minValue = DateTime::MinDateTime();
   assert(minValue.Year() == 1);
   assert(minValue.Month() == 1);
   assert(minValue.Day() == 1);

   t = DateTime(1970, 1, 2);
   assert(DateTime::GetEpochFromDateTime(t) == 60 * 60 * 24);
   DateTime epochDT = DateTime::GetDateTimeFromEpoch(60 * 60 * 48);
   assert(epochDT.Year() == 1970);
   assert(epochDT.Month() == 1);
   assert(epochDT.Day() == 3);

   t = t + TimeDuration(0, 3, 34);
   assert(t.Year() == 1970);
   assert(t.Month() == 1);
   assert(t.Day() == 2);
   assert(t.Hour() == 0);
   assert(t.Min() == 3);
   assert(t.Sec() == 34);

   TimeDuration tempTD = t - DateTime(1970, 1, 2);
   assert(tempTD.Mins() == 3);
   assert(tempTD.Seconds() == 34);

   t = t - TimeDuration(0, 3, 35);
   assert(t.Year() == 1970);
   assert(t.Month() == 1);
   assert(t.Day() == 1);
   assert(t.Hour() == 23);
   assert(t.Min() == 59);
   assert(t.Sec() == 59);
}

static void TestCmdLineParser(void)
{
   cppmempool::MemPoolWrap memPool;

   try {
      pcwstr_t argv[10] = { _S("hello.exe"),
                           _S("-c"),
                           _S("-y"),
                           _S("--longopt"),
                           _S("-DARG"),
                           _S("-Dwww=\"ppp\""),
                           _S("-Dwwe=123"),
                           _S("a1.c"),
                           _S("a2.c"),
                           _S("a3.c")
                        };

      CFString name, val;
      CmdLineParser *pCmdParser = new CmdLineParser(10, const_cast<pwstr_t*>(argv), NULL);
      
      assert(pCmdParser->GetProgramName() == _S("hello.exe"));
      assert(pCmdParser->GetTotalOptionCount() == 4);

      assert(pCmdParser->GetOption(0) == _S("-c"));
      assert(pCmdParser->GetOptionCount(_S("-c")) == 1);
      assert(pCmdParser->GetOption(_S("-c"), 0, name, val));
      assert(name == _S(""));
      assert(val == _S(""));

      assert(pCmdParser->GetOption(1) == _S("-y"));
      assert(pCmdParser->GetOptionCount(_S("-y")) == 1);
      assert(pCmdParser->GetOption(_S("-y"), 0, name, val));
      assert(name == _S(""));
      assert(val == _S(""));

      assert(pCmdParser->GetOption(2) == _S("--longopt"));
      assert(pCmdParser->GetOptionCount(_S("--longopt")) == 1);
      assert(pCmdParser->GetOption(_S("--longopt"), 0, name, val));
      assert(name == _S(""));
      assert(val == _S(""));

      assert(pCmdParser->GetOption(3) == _S("-D"));
      assert(pCmdParser->GetOptionCount(_S("-D")) == 3);
      assert(pCmdParser->GetOption(_S("-D"), 0, name, val));
      assert(name == _S("ARG"));
      assert(val == _S(""));
      assert(pCmdParser->GetOption(_S("-D"), 1, name, val));
      assert(name == _S("www"));
      assert(val == _S("ppp"));
      assert(pCmdParser->GetOption(_S("-D"), 2, name, val));
      assert(name == _S("wwe"));
      assert(val == _S("123"));
      
      assert(pCmdParser->GetUnclassifiedCount() == 3);
      assert(pCmdParser->GetUnclassified(0) == _S("a1.c"));
      assert(pCmdParser->GetUnclassified(1) == _S("a2.c"));
      assert(pCmdParser->GetUnclassified(2) == _S("a3.c"));
   }
   catch(exceptions::BaseException &) {
      assert(false);
   }
}

static void TestCmdLineParser_2(void)
{
   cppmempool::MemPoolWrap memPool;

   try {
      pcwstr_t argv[15] = { _S("cc.exe"),
                           _S("-o"),
                           _S("abc"),
                           _S("-o"),
                           _S("hh=123"),
                           _S("-u"),
                           _S("rr.bmp"),
                           _S("--longopt"),
                           _S("qw=0987"),
                           _S("--longopt"),
                           _S("ww=ddd"),
                           _S("--longopt"),
                           _S("9p"),
                           _S("a2.c"),
                           _S("a3.c")
                        };

      pcwstr_t optWithArg[] = {  _S("-o"),
                                 _S("--longopt"),
                                 NULL
                              };

      CFString name, val;
      CmdLineParser *pCmdParser = new CmdLineParser(15, const_cast<pwstr_t*>(argv), optWithArg);
      
      assert(pCmdParser->GetTotalOptionCount() == 3);
      assert(pCmdParser->GetOption(0) == _S("-o"));
      assert(pCmdParser->GetOptionCount(_S("-o")) == 2);
      assert(pCmdParser->GetOption(_S("-o"), 0, name, val));
      assert(name == _S("abc"));
      assert(val == _S(""));
      assert(pCmdParser->GetOption(_S("-o"), 1, name, val));
      assert(name == _S("hh"));
      assert(val == _S("123"));

      assert(pCmdParser->GetOption(1) == _S("-u"));
      assert(pCmdParser->GetOptionCount(_S("-u")) == 1);
      assert(pCmdParser->GetOption(_S("-u"), 0, name, val));
      assert(name == _S(""));
      assert(val == _S(""));
      
      assert(pCmdParser->GetOption(2) == _S("--longopt"));
      assert(pCmdParser->GetOptionCount(_S("--longopt")) == 3);
      assert(pCmdParser->GetOption(_S("--longopt"), 0, name, val));
      assert(name == _S("qw"));
      assert(val == _S("0987"));
      assert(pCmdParser->GetOption(_S("--longopt"), 1, name, val));
      assert(name == _S("ww"));
      assert(val == _S("ddd"));
      assert(pCmdParser->GetOption(_S("--longopt"), 2, name, val));
      assert(name == _S("9p"));
      assert(val == _S(""));

      assert(pCmdParser->GetUnclassifiedCount() == 3);
      assert(_S("rr.bmp") == pCmdParser->GetUnclassified(0));
      assert(_S("a2.c") == pCmdParser->GetUnclassified(1));
      assert(_S("a3.c") == pCmdParser->GetUnclassified(2));

   }
   catch(exceptions::BaseException &) {
      assert(false);
   }

}

static void TestCmdLineParser_3(void)
{
   cppmempool::MemPoolWrap memPool;

   try {
      pcwstr_t argv[29] = { _S("cc.exe"),
                           _S("-d"), _S("=33"),
                           _S("-d"), _S("\"123\""),
                           _S("-d"), _S("dd=\"123"),
                           _S("-d"), _S("dt=\"123 dd\"ttt"),
                           _S("-d"), _S("\"da=\"123 = dd\""),
                           _S("-d"), _S("da1="),
                           _S("-d"), _S("da3=\"\""),
                           _S("-d"), _S("da3=34\""),
                           _S("-d"), _S("da4=\""),
                           _S("-d"), _S("="),
                           _S("-d"), _S("=\"78\""),
                           _S("-d"), _S("=78\""),
                           _S("-d"), _S("=\"78"),
                           _S("-d"), _S("rr\"")
                         };

      pcwstr_t optWithArg[] = {  _S("-d"),
                                 NULL
                              };

      CFString name, val;
      CmdLineParser *pCmdParser = new CmdLineParser(29, const_cast<pwstr_t*>(argv), optWithArg);

      assert(pCmdParser->GetTotalOptionCount() == 1);
      assert(pCmdParser->GetOption(0) == _S("-d"));

      int index = 0;
      assert(pCmdParser->GetOptionCount(_S("-d")) == 10);
      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S("\"123\""));
      assert(val == _S(""));
      
      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S("dd"));
      assert(val == _S("123"));

      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S("dt"));
      assert(val == _S("123 dd"));

      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S("\"da"));
      assert(val == _S("123 = dd"));
      
      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S("da1"));
      assert(val == _S(""));

      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S("da3"));
      assert(val == _S(""));

      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S("da3"));
      assert(val == _S("34\""));

      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S("da4"));
      assert(val == _S(""));
      
      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S(""));
      assert(val == _S(""));

      assert(pCmdParser->GetOption(_S("-d"), index++, name, val));
      assert(name == _S("rr\""));
      assert(val == _S(""));

   }
   catch(exceptions::BaseException &) {
      assert(false);
   }

}

static void TestRandom(void)
{
   cppmempool::MemPoolWrap memPool;

   Random *pRand = new Random();
   Random &rand = *pRand;
    

   int n = rand.GetInt32();
   debug::Print(debug::DL_INFO, _S("rand num = %d\n"), n);

   n = rand.GetInt32(9999, 1029383);
   debug::Print(debug::DL_INFO, _S("rand num = %d\n"), n);
   assert(n >= 9999 && n <= 1029383);

   n = rand.GetInt32(0x11222, 0xf1222);
   debug::Print(debug::DL_INFO, _S("rand num = 0x%x\n"), n);
   assert(n >= 0x11222 && n <= 0xf1222);

   i64_t n64 = rand.GetInt64();
   debug::Print(debug::DL_INFO, _S("rand num 64 = 0x%x\n"), n64);

   n64 = rand.GetInt64(0x222, I64N(0xfffffffffff));
   debug::Print(debug::DL_INFO, _S("rand num 64 = 0x%x\n"), n64);
   assert(n64 >= 0x222 && n64 <= I64N(0xfffffffffff));

   n64 = rand.GetInt64(I64N(0x61fffffffff), I64N(0x73ffffffffff));
   debug::Print(debug::DL_INFO, _S("rand num 64 = 0x%x\n"), n64);
   assert(n64 >= I64N(0x61fffffffff) && n64 <= I64N(0x73ffffffffff));

   ArrayByte *pArray = new ArrayByte(32);

   rand.GetBytes(*pArray, 5, 10);
   for (u32_t i = 0; i < pArray->GetSize(); ++i) {
      if (i < 5 || i >= 15) {
         assert((*pArray)[i] == 0);
      }
   }

   rand.GetBytes(*pArray);

   CFString str;
   const int num = 24;
   rand.GetString(str, Random::RT_DECDIGIT, num);
   assert(str.GetLength() == num);
   debug::Print(debug::DL_INFO, _S("rand str (dec digits only) = %s\n"), static_cast<pcwstr_t>(str));
   for (int i = 0; i < str.GetLength(); ++i) {
      wc_t c = str[i];
      assert(str[i] >= _S('0') && str[i] <= _S('9'));
   }

   rand.GetString(str, Random::RT_HEXDIGIT, num);
   assert(str.GetLength() == num);
   debug::Print(debug::DL_INFO, _S("rand str (hex digits only) = %s\n"), static_cast<pcwstr_t>(str));
   for (int i = 0; i < str.GetLength(); ++i) {
      wc_t c = str[i];
      assert((str[i] >= _S('0') && str[i] <= _S('9')) || (str[i] >= _S('A') && str[i] <= _S('F')));
   }

   rand.GetString(str, Random::RT_ALPHANUMERIC, num);
   assert(str.GetLength() == num);
   debug::Print(debug::DL_INFO, _S("rand str (alphanumeric) = %s\n"), static_cast<pcwstr_t>(str));
   for (int i = 0; i < str.GetLength(); ++i) {
      wc_t c = str[i];
      assert((str[i] >= _S('0') && str[i] <= _S('9')) || (str[i] >= _S('A') && str[i] <= _S('Z')));
   }

   rand.GetString(str, Random::RT_ALPHANUMERIC_NOCASE, num);
   assert(str.GetLength() == num);
   debug::Print(debug::DL_INFO, _S("rand str (alphanumeric case sensitive) = %s\n"), static_cast<pcwstr_t>(str));
   for (int i = 0; i < str.GetLength(); ++i) {
      wc_t c = str[i];
      assert((str[i] >= _S('0') && str[i] <= _S('9')) || (str[i] >= _S('A') && str[i] <= _S('Z')) || (str[i] >= _S('a') && str[i] <= _S('z')));
   }

   rand.GetString(str, Random::RT_UPPERCASE, num);
   assert(str.GetLength() == num);
   debug::Print(debug::DL_INFO, _S("rand str (upper case only) = %s\n"), static_cast<pcwstr_t>(str));
   for (int i = 0; i < str.GetLength(); ++i) {
      wc_t c = str[i];
      assert(str[i] >= _S('A') && str[i] <= _S('Z'));
   }

   rand.GetString(str, Random::RT_LOWERCASE, num);
   assert(str.GetLength() == num);
   debug::Print(debug::DL_INFO, _S("rand str (lower case only) = %s\n"), static_cast<pcwstr_t>(str));
   for (int i = 0; i < str.GetLength(); ++i) {
      wc_t c = str[i];
      assert(str[i] >= _S('a') && str[i] <= _S('z'));
   }

}

static void TestFileSys(void)
{
   debug::Print(_S("Testing FileSys ...\n"));

   cppmempool::MemPoolWrap memPool;

#if defined(WIN32)
   assert(os::FileExists(_S("Testcppflib.exe")));
#elif defined(linux)
   assert(os::FileExists(_S("Testcppflib")));
#endif

   assert(!os::FileExists(_S("xyz1234")));

   // make a temp file 
   try {
      u8_t c = static_cast<u8_t>('a');
      FileStream *fs = new FileStream(_S("test.txt"), FileStream::FA_WRITE);   
      fs->Write(c);
      fs->Close();
   }
   catch (IOException &exp) {
      debug::Print(exp.GetMsg());
      assert(false);
   }

   assert(os::CpFile(_S("test.txt"), _S("test_1.txt"), true));
   assert(!os::CpFile(_S("test.txt"), _S("test_1.txt"), true));
   assert(os::MvFile(_S("test_1.txt"), _S("test_2.txt"), true));
   assert(os::DelFile(_S("test.txt")));
   assert(os::DelFile(_S("test_2.txt")));

   CFString szCurDir, szDir;
   os::GetCurDirectory(szCurDir);
   assert(os::MakeDirectory(_S("../hello/world/"), true));
   assert(os::ChangeDirectory(_S("../hello/world")));
   os::GetCurDirectory(szDir);
   assert(szDir.Find(_S("hello")) >= 0);
   assert(szDir.Find(_S("world")) >= 0);
   assert(os::ChangeDirectory(_S("../..")));
   assert(os::DelDirectory(_S("hello/world")));
   assert(os::DelDirectory(_S("hello")));
   assert(os::ChangeDirectory(szCurDir));

   CFString szTempName;
   os::File *pFile = File::GetInstance(_S("kckc/ddss"));
   assert(pFile == NULL);
   szDir.Format(_S("..%s../"), File::DirSeparator);
   pFile = File::GetInstance(szDir);
   assert(pFile != NULL);
#if defined(WIN32)
   pcwstr_t pRoot = _S("C:\\");   
#elif defined(linux)
   pcwstr_t pRoot = _S("/");
#endif
   pFile = File::GetInstance(pRoot);
   assert(pFile != NULL);
   pFile->GetParent(szTempName);
   debug::Print(debug::DL_INFO, _S("parent = %s\r\n"), static_cast<pcwstr_t>(szTempName));
   assert(szTempName == pRoot);

   pFile = File::GetInstance(File::DirSeparator); // drive letter will be prepended
   assert(pFile != NULL);

   pFile = File::GetInstance(_S("."));
   assert(pFile != NULL);
   assert(pFile->IsDir());
   assert(pFile->CanRead());
   assert(pFile->CanWrite());
#if defined(WIN32)
   assert(!pFile->CanExecute());
#endif
   assert(!pFile->IsFile());
   assert(!pFile->IsHidden());
   DateTime tc = pFile->GetCreationTime();
   DateTime tm = pFile->GetLastModifiedTime();
   assert(tm >= tc);
   debug::Print(debug::DL_INFO, _S("createtime = %s\r\n"), tc.ToString());
   debug::Print(debug::DL_INFO, _S("lastmod = %s\r\n"), tm.ToString());

   CFString szTempFile, absPath;
   pFile->GetAbsolutePath(absPath);
   pFile->GetName(szTempFile);
   assert(absPath.EndsWith(szTempFile));
   pFile->GetParent(szTempFile);
   assert(absPath.StartsWith(szTempFile));

   ListCppObjT<File> * fileList = pFile->GetChildFiles();
   assert(fileList != NULL);
   assert(fileList->GetCount() > 0);
   for (int i = 0; i < static_cast<int>(fileList->GetCount()); ++i) {
      fileList->Get(i)->GetAbsolutePath(szTempFile);
      assert(fileList->Get(i)->CanRead());
      debug::Print(debug::DL_INFO, _S("%s\r\n"), static_cast<pcwstr_t>(szTempFile));
#if defined(WIN32)
      if (szTempFile.EndsWith(_S(".exe"))) {
#elif defined(linux)
      if (!szTempFile.EndsWith(_S(".o"))) {
#endif
         assert(fileList->Get(i)->CanExecute());
      }

      if (fileList->Get(i)->IsFile()) {
         assert(fileList->Get(i)->GetChildFiles() == NULL);
      }
   }
   
}

static void TestAtomicOperations()
{
   volatile u32_t num = 0;
   assert(util::AtomicIncrementFetch(&num) == 1);
   assert(util::AtomicRead(&num) == 1);
   assert(util::AtomicDecrementFetch(&num) == 0);
   assert(util::AtomicRead(&num) == 0);
}

static void TestDeflater()
{
   cppmempool::MemPoolWrap memPool;

   // gzip one file
   Deflater *pDeflater = new Deflater(Deflater::GZIP);
   FileStream *pStream = new FileStream(_S("../../extlib/openssl/win32/bin/rel/libeay32.dll"), FileStream::FA_READONLY);
   FileStream *outStream = new FileStream(_S("out.gz"), FileStream::FA_WRITE);
   ArrayByte buffer(256);

   pDeflater->SetInputStream(pStream);
   int nrBytes = 0;
   do {
      nrBytes = pDeflater->Deflate(buffer);
      if (nrBytes <= 0)
         break;

      outStream->Write(buffer, 0, nrBytes);
   } while(true);

}

static void TestInflater()
{
   cppmempool::MemPoolWrap memPool;

   // gunzip one file
   Inflater *pInflater = new Inflater(Inflater::AUTODETECT);
   FileStream *pStream = new FileStream(_S("out.gz"), FileStream::FA_READONLY);
   FileStream *outStream = new FileStream(_S("out.txt"), FileStream::FA_WRITE);
   ArrayByte buffer(256);

   pInflater->SetInputStream(pStream);
   int nrBytes = 0;
   do {
      nrBytes = pInflater->Inflate(buffer);
      if (nrBytes <= 0)
         break;

      outStream->Write(buffer, 0, nrBytes);
   } while(true);
}


static void __TestDeflaterInflater(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   // gzip one file
   Deflater *pDeflater = new Deflater(Deflater::GZIP);
   FileStream *pStream = new FileStream(filePath, FileStream::FA_READONLY);
   MemoryStream *gzippedStream = new MemoryStream();  // output to a memory stream
   ArrayByte buffer(256);

   pDeflater->SetInputStream(pStream);
   int nrBytes = 0;
   do {
      nrBytes = pDeflater->Deflate(buffer);
      if (nrBytes <= 0)
         break;

      gzippedStream->Write(buffer, 0, nrBytes);
   } while(true);

   gzippedStream->ResetPointer();
   
   // gunzip the stream
   Inflater *pInflater = new Inflater(Inflater::AUTODETECT);
   MemoryStream *plainByteStream = new MemoryStream();

   pInflater->SetInputStream(gzippedStream, gzippedStream->GetBufferSize());
   nrBytes = 0;
   do {
      nrBytes = pInflater->Inflate(buffer);
      if (nrBytes <= 0)
         break;

      plainByteStream->Write(buffer, 0, nrBytes);
   } while(true);


   // compare the gunzipped and the original stream byte by byte
   plainByteStream->ResetPointer();
   pStream->Seek(0, Stream::S_BEGIN);
   assert(static_cast<sz_t>(pStream->GetFileSize()) == plainByteStream->GetBufferSize());
   int src, dest;
   for (sz_t i = 0; i < plainByteStream->GetBufferSize(); ++i) {
      src = pStream->Read();
      dest = plainByteStream->Read();
      assert(src == dest);
   }

}


static void TestDeflaterInflater()
{
   debug::Print(_S("Testing gzip/gunzip ...\n"));

   FileStruct * xmlFiles = GetXmlFiles();

   try {

      for (int i = 0; xmlFiles[i].filePath && xmlFiles[i].involveInFullTest; ++i) {
         //debug::Print(debug::DL_INFO, _S("file = %s\n"), xmlFiles[i].filePath);
         __TestDeflaterInflater(xmlFiles[i].filePath);
      }

   }
   catch(BaseException &e) {
      debug::Print(debug::DL_DEBUG, _S("err = %s, code = %d\n"), e.GetMsg(), e.GetErrCode());
      assert(false);
   }
}

static void TestDebugClass()
{
   debug::Print(_S("Testing os::DebugLog ...\n"));

   cppmempool::MemPoolWrap memPool;
   // print to console
   debug::DebugLog *pLog = new debug::DebugLog(_S("ConsoleLog"));
   pLog->Print(_S("Hello1 Log, Hello2 Log, Hello3 Log, Hello4 Log, Hello5 Log !!!\n"));
   pLog->Print(debug::DL_ERROR, _S("An error log: reason = %s, error code = %d\n"), _S("unknown"), 339);
   pLog->Print(debug::DL_INFO, CFString(_S("Hello6 Log, Hello7 Log, Hello8 Log, Hello9 Log, Hello10 Log!\n")));
   pLog->PlainPrint(_S("OK ... nothing !@#$&^\n"));
   pLog->Close();
   
   pcwstr_t logFile = _S("mylog.txt");

   // print to file
   pLog = new debug::DebugLog(_S("FileLog"), logFile, false);
   pLog->Print(_S("Hello1 Log, Hello2 Log, Hello3 Log, Hello4 Log, Hello5 Log !!!\n"));
   pLog->Print(debug::DL_ERROR, _S("An error log: reason = %s, error code = %d\n"), _S("unknown"), 339);
   pLog->Print(debug::DL_INFO, CFString(_S("Hello6 Log, Hello7 Log, Hello8 Log, Hello9 Log, Hello10 Log!\n")));
   pLog->PlainPrint(_S("OK ... nothing !@#$&^\n"));
   pLog->Close();

   os::DelFile(logFile);
}

void TestUtil(void)
{
   debug::Print(_S("Testing util ...\n"));

   TestTimeDuration();
   TestDateTime();
   TestDateTime2();
   TestDateTime3();
   TestDateTime4();
   TestDateTime5();
   TestCmdLineParser();
   TestCmdLineParser_2();
   TestCmdLineParser_3();
   TestRandom();
   TestFileSys();
   TestAtomicOperations();
   //TestDeflater();
   //TestInflater();
   TestDeflaterInflater();
   TestDebugClass();
}
